#ifndef AVALON_BUFFEREDREADER_HPP
#define AVALON_BUFFEREDREADER_HPP
#include "Avalon/Base/Handle.hpp"
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/PipedMessageReader.hpp"
#include "Avalon/IO/PipedMessageWriter.hpp"
#include "Avalon/IO/Reader.hpp"

namespace Avalon {
namespace IO {

  /*! \class BufferedReader
   *  \brief Buffers all data read from another Reader.
   */
  class BufferedReader : public Reader {
    public:

      //! Constructs a BufferedReader.
      /*!
        \param source The Reader to buffer.
      */
      BufferedReader(Carry<Reader> source);

      virtual ~BufferedReader();

      virtual void Read(Buffer* destination,
        Out<Threading::Async<int> > sizeRead);

      virtual void Read(void* destination, int size,
        Out<Threading::Async<int> > sizeRead);

      virtual void Read(Buffer* destination, int size,
        Out<Threading::Async<int> > sizeRead);

    private:
      boost::mutex m_mutex;
      Handle<Reader> m_source;
      PipedMessageReader m_reader;
      PipedMessageWriter m_writer;
      Avalon::Threading::Async<int> m_sizeRead;
      Avalon::Threading::Async<int>::FinishedSlot m_readSlot;
      bool m_isBuffering;
      Buffer m_destination;

      void EnableBuffering(boost::unique_lock<boost::mutex>& lock);
      void BufferReads(boost::unique_lock<boost::mutex>& lock);
      void OnRead();
  };
}
}

#endif // AVALON_BUFFEREDREADER_HPP
